package teamExtreme;

import java.io.*;
import java.util.*;
import java.awt.Desktop;
import org.apache.poi.xssf.usermodel.*;

public class GuiFunctions
{
    public GuiFunctions(File file)
    {
        try
        {
            //full path of file
            OUT_PATH = file.getPath();
            //removes .xlsx from path
            OUT_PATH = OUT_PATH.substring(0, OUT_PATH.indexOf(".xlsx"));
            //appends .output.xlsx to path
            OUT_PATH = OUT_PATH + ".output.xlsx";
            
            //stream used to read from input file
            FileInputStream istream = new FileInputStream(file.getPath());
            poi_workbook = new XSSFWorkbook(istream);
            
            numberOfStudents = poi_workbook.getSheetAt(0).getLastRowNum() + 1;
            
            groupSize = 5;
            normalGroups = 0;
            oneLessGroups = 0;
            projGrpCount = 0;
            groups();
            
            //project groups needs this defined here, so it's not regenerated
            //every time the button is pushed
            cellBlacklist = new XSSFCell[numberOfStudents];
            blacklistCount = 0;
            
            //remove any empty sheets
            for(int i = (poi_workbook.getNumberOfSheets() - 1); i >= 0; --i)
            {
                if(poi_workbook.getSheetAt(i).getLastRowNum() == 0)
                    poi_workbook.removeSheetAt(i);
            }
            
            //set sheet[0]'s name to master sheet
            poi_workbook.setSheetName(0, "Master Sheet");
            
            //create a copy of the original masterFile
            writeWorkbook();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    
    //returns a random master sheet cell
    public XSSFCell randCell()
    {
        Random rand = new Random();
        int x = rand.nextInt(numberOfStudents);
        
        XSSFCell cell = poi_workbook.getSheetAt(0).getRow(x).getCell(0);
        
        return cell;
    }
    
    public boolean isCellBlacklisted(XSSFCell cell)
    {
        String s1;
        String s2 = cell.getStringCellValue();
        for(int i = 0; i < blacklistCount; ++i)
        {
            s1 = cellBlacklist[i].getStringCellValue();
            if(s1.equalsIgnoreCase(s2))
                return true;
        }
        
        cellBlacklist[blacklistCount] = cell;
        ++blacklistCount;
        return false;
    }
    
    private void openFile(File file)
    {
        try
        {
            //use Desktop to open masterFile (defaults to excel)
            Desktop desktop = Desktop.getDesktop();
            desktop.open(file);
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
    }

    //determines if excel is currently running
    private void killExcel()
    {
        try
        {
            Runtime.getRuntime().exec("taskkill /IM EXCEL.EXE");
            
            boolean alive = true;
            while(alive)
            {
                Process p = Runtime.getRuntime().exec("tasklist");
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(p.getInputStream())
                );
                String line;
                while ((line = reader.readLine()) != null)
                {
                    System.out.println(line);
                    if (line.contains("EXCEL.EXE"))
                    {
                        alive = true;
                        break;
                    }
                    else
                        alive = false;
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    
  //determine the number of groups
    private void groups()
    {
        if((numberOfStudents % groupSize) == 0)
            //oneLessGroups is 0 by default
            normalGroups = numberOfStudents / groupSize;
        else 
        {
            int x = numberOfStudents;
            ++oneLessGroups;
            
            //calculate normalGroups
            while((x = x - (groupSize - 1)) % (groupSize) != 0)
                ++oneLessGroups;
            
            int i;
            for(i = 0; x > 0; ++i)
                x = x - groupSize;
            
            normalGroups = i;
        }
    }
    

    private void writeWorkbook()
    {
        try
        {
            killExcel();
            
            //use ostream to write to output file
            FileOutputStream ostream = new FileOutputStream(OUT_PATH);
            poi_workbook.write(ostream);
            ostream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    
    private void subInit(String sheetName, int sheetIndex)
    {
        //need this here so saving takes effect when excel prompts for it
        killExcel();
        
        //try to set the workbook to the output file
        try
        {
            poi_workbook = new XSSFWorkbook(new FileInputStream(OUT_PATH));
            
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        
        //if a sheet with the same name exists
        if(poi_workbook.getSheet(sheetName) != null)
        {
            //Project Groups (tab4) needs to keep using same sheet
            if(sheetName == "Project Groups")
                poi_sheet = poi_workbook.getSheet(sheetName);
            else
            {
                poi_workbook.removeSheetAt(poi_workbook.getSheetIndex(sheetName));
                if(poi_workbook.getSheet("Project Groups") != null)
                {
                    poi_workbook.removeSheetAt(poi_workbook.getSheetIndex("Project Groups"));
                    projGrpCount = 0;
                }
                    
                poi_sheet = poi_workbook.createSheet(sheetName);
            }
        }
        else
            poi_sheet = poi_workbook.createSheet(sheetName);
        
        //if the created sheet's index is not equal to the parsed sheet index
        //set the sheet index to the created sheet's current index
        if(poi_workbook.getSheetIndex(sheetName) < sheetIndex)
            sheetIndex = poi_workbook.getSheetIndex(sheetName);
        
        poi_workbook.setSheetOrder(sheetName, sheetIndex);
        poi_workbook.setActiveSheet(sheetIndex);
        
        poi_style = poi_workbook.createCellStyle();
        poi_font = poi_workbook.createFont();
    }
    
    //NOTE: no destructors in java, this is a helper function similar to
    //a destructor. To be called at the end of each sub class
    private void subClose()
    {
        //auto-adjust width of columns
        for(int i = 0; i < poi_sheet.getRow(poi_sheet.getFirstRowNum()).getLastCellNum(); ++i)
            poi_sheet.autoSizeColumn(i);
        
        writeWorkbook();
        openFile(new File(OUT_PATH));
        
        //Project Groups needs to keep the same blacklist stuff
        if(!(poi_sheet.getSheetName().equalsIgnoreCase("Project Groups")))
        {
            blacklistCount = 0;
            cellBlacklist = new XSSFCell[numberOfStudents];
            
            //recalculate groups in case random groups was just ran
            groupSize = 5;
            normalGroups = 0;
            oneLessGroups = 0;
            groups();
        }
    }
    
/******************************************************************************/
    public class RandList
    {
        public RandList()
        {
            cellBlacklist = new XSSFCell[numberOfStudents];
            blacklistCount = 0;
            
            subInit("Random List", 1);
        }
        
        public void genRandList()
        {
            for(int i = 0; i < numberOfStudents; ++i)
            {
                poi_cell = randCell();

                //if the cell was not blacklisted, insert it
                if(!isCellBlacklisted(poi_cell))
                    poi_sheet.createRow(i).createCell(0).setCellValue(poi_cell.getStringCellValue());
                    
                //otherwise, decrement counter to search for another cell
                else
                    --i;
            }
            subClose();
        }
    }
    
/******************************************************************************/
    public class RandGroups
    {
        public RandGroups(int gSize)
        {
            cellBlacklist = new XSSFCell[numberOfStudents];
            blacklistCount = 0;
            
            subInit("Random Groups", 2);
            
            groupSize = gSize;
            normalGroups = 0;
            oneLessGroups = 0;
        }
        
        public void genRandGroups()
        {
            groups();
            
            for(int i = 0; i < normalGroups; ++i)
            {
                XSSFRow tmpRow = poi_sheet.createRow(i);
                for(int j = 0; j < groupSize; ++j)
                {
                    poi_cell = randCell();
                    
                    if(!isCellBlacklisted(poi_cell))
                    {
                        tmpRow.createCell(j).setCellValue
                                    (poi_cell.getStringCellValue());
                    }
                    else
                        --j;
                }
            }
            
            for(int i = 0; i < oneLessGroups; ++i)
            {
                XSSFRow tmpRow = poi_sheet.createRow(poi_sheet.getLastRowNum() + 1);
                for(int j = 0; j < (groupSize - 1); ++j)
                {
                    poi_cell = randCell();
                    
                    if(!isCellBlacklisted(poi_cell))
                    {
                        tmpRow.createCell(j).setCellValue
                                    (poi_cell.getStringCellValue());
                    }
                    else
                        --j;
                }
            }
            subClose();
        }
    }

/******************************************************************************/
    public class SoireeList
    {
        public SoireeList()
        {
            subInit("Soiree List", 3);
            
            nameCount = new int[numberOfStudents];
        }
        
        public void genSoireeList()
        {
            poi_font.setBold(true);
            poi_style.setFont(poi_font);
            
            for(int i = 0; i < numberOfStudents; ++i)
            {
                //get cell from master list
                XSSFCell masterCell = poi_workbook.getSheetAt(0).getRow(i).getCell(0);
                String masterName, soireeName;
                int count;
                masterName = masterCell.getStringCellValue();
                
                //set sheet cell to master cell value
                poi_cell = poi_sheet.createRow(i).createCell(0);
                poi_cell.setCellStyle(poi_style);
                poi_cell.setCellValue(masterName);
                isCellBlacklisted(masterCell);
                
                //generate soiree list
                for(int j = 1; j <= 12; ++j)
                {
                    XSSFCell randCell = randCell();
                    soireeName = randCell.getStringCellValue();
                    int row = randCell.getRowIndex();
                    count = nameCount[row];
                    if(count <= 12 && !isCellBlacklisted(randCell))
                    {
                        poi_sheet.getRow(i).createCell(j).setCellValue(randCell.getStringCellValue());
                        ++count;
                        nameCount[randCell.getRowIndex()] = count;
                    }
                    else
                        --j;
                }
                
                cellBlacklist = new XSSFCell[numberOfStudents];
                blacklistCount = 0;
            }
            subClose();
        }
    }
    
    private int nameCount[];
    
/******************************************************************************/
    public class ProjectGroups
    {
        public ProjectGroups(String n1, String n2)
        {
            name1 = n1;
            name2 = n2;
            
            valid = validNames();
            
            //if the names are invalid then return without calling subInit
            if(!valid)
                return;
            
            subInit("Project Groups", 4);
            
            if(projGrpCount < 1)
            {
                String masterName = null;
                for(int i = 0; i <= numberOfStudents; ++i)
                {
                    if(i != numberOfStudents)
                    {
                        //get the name of the cell
                        masterName = poi_workbook.getSheetAt(0).getRow(i).getCell(0).getStringCellValue();
                    }
                    poi_sheet.createRow(i).createCell(6).setCellValue(masterName);
                }
            }
            //reserve first row for formatting
            poi_row = poi_sheet.getRow(projGrpCount + 1);
            
            poi_row.createCell(0).setCellValue(name1);
            poi_row.createCell(1).setCellValue(name2);
        }
        
        //check if the names are listed in the master sheet
        public boolean validNames()
        {
            XSSFSheet masterSheet = poi_workbook.getSheetAt(0);
            String cellValue;
            
            //check if the names entered are in master list
            for(int i = 0; i < numberOfStudents; ++i)
            {
                cellValue = masterSheet.getRow(i).getCell(0).getStringCellValue();
                if(c1 == null)
                {
                    if(cellValue.equalsIgnoreCase(name1))
                        c1 = masterSheet.getRow(i).getCell(0);
                }
                if(c2 == null)
                {
                    if(cellValue.equalsIgnoreCase(name2))
                        c2 = masterSheet.getRow(i).getCell(0);
                }
            }
            if(c1 == null || c2 == null)
                return false;
            if(isCellBlacklisted(c1) || isCellBlacklisted(c2))
                return false;
            else
                return true;
        }
        
        public boolean getValid()
        {
            return valid;
        }
        
        public void genProjectGroups()
        {
            if(projGrpCount < normalGroups)
            {
                for(int i = 2; i < groupSize; ++i)
                {
                    XSSFCell tmpCell = randCell();
                    if(!isCellBlacklisted(tmpCell))
                        poi_row.createCell(i).setCellValue(tmpCell.getStringCellValue());
                    else
                        --i;
                }
                ++projGrpCount;
            }
            
            else if(projGrpCount < (normalGroups + oneLessGroups))
            {
                for(int i = 2; i < groupSize - 1; ++i)
                {
                    XSSFCell tmpCell = randCell();
                    if(!isCellBlacklisted(tmpCell))
                        poi_row.createCell(i).setCellValue(tmpCell.getStringCellValue());
                    else
                        --i;
                }
                ++projGrpCount;
            }
            
            //available students list
            for(int i = 0; i < numberOfStudents; ++i)
            {
                String masterName = poi_workbook.getSheetAt(0).getRow(i).getCell(0).getStringCellValue();
                for(int j = 0; j < blacklistCount; ++j)
                {
                    if(masterName.equalsIgnoreCase(cellBlacklist[j].getStringCellValue()))
                    {
                        poi_sheet.getRow(i+1).getCell(6).setCellValue("");
                        break;
                    }
                    else
                        poi_sheet.getRow(i+1).getCell(6).setCellValue(masterName);
                }
            }
            
            //set the font for generated groups
            poi_font.setBold(true);
            poi_style.setFont(poi_font);
            
            poi_cell = poi_sheet.getRow(0).createCell(0);
            poi_cell.setCellStyle(poi_style);
            poi_cell.setCellValue("Generated Groups:");
            
            //set the font for available students
            poi_cell = poi_sheet.getRow(0).getCell(6);
            poi_cell.setCellStyle(poi_style);
            poi_cell.setCellValue("Available Students:");
            
            subClose();
        }
        
        XSSFCell c1, c2;
        private String name1, name2;
        boolean n1Valid, n2Valid, valid;
    }
    
/******************************************************************************/
    private XSSFWorkbook poi_workbook;
    private XSSFSheet poi_sheet;
    private XSSFRow poi_row;
    private XSSFCell poi_cell;
    private XSSFCellStyle poi_style;
    private XSSFFont poi_font;
    
    private XSSFCell[] cellBlacklist;
    
    private int numberOfStudents, blacklistCount;
    private int groupSize, oneLessGroups, normalGroups, projGrpCount;
    private String OUT_PATH;
}
